package com.bysc.commonutils.utils;

import com.bysc.commonutils.enums.CommentEnum;
import com.bysc.commonutils.vo.PostStatsVo;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;

/**
 * 热度评分工具类
 */
@Slf4j
@Data
@Component
public class ScoreUtil {

    // 默认权重
    private static final double LIKE_WEIGHT = 1.0;
    private static final double FAVORITE_WEIGHT = 1.5;
    private static final double VIEW_WEIGHT = 0.5;
    private static final double COMMENT_WEIGHT = 2.0;

    // 时间衰减因子，每天的衰减率（基础值）
    private static final double DECAY_RATE = 0.95;

    // 最大的评论数权重
    private static final int MAX_COMMENT_WEIGHT = 20; // 允许评论数的最大权重

    // 最大浏览量权重
    private static final int MAX_VIEW_WEIGHT = 1000; // 限制浏览量权重，避免失真

    // 时间衰减的特殊策略：根据内容的生命周期调整衰减
    private static final int SHORT_LIVED_CONTENT_DAYS = 7; // 短期内容的天数阈值
    // 用户类型权重
    private static final double ACTIVE_USER_WEIGHT = 1.2; // 活跃用户权重
    private static final double ASSOCIATION_MEMBER_WEIGHT = 1.3; // 协会成员权重
    private static final double ASSOCIATION_LEADER_WEIGHT = 1.5; // 协会会长权重

    /**
     * 计算内容的热度得分
     *
     * @param postStats        帖子统计数据
     * @param creationDateTime 内容创建的Date
     * @param contentType      内容类型（学习资料/帖子）
     * @return 内容的热度得分
     */
    public static double calculateHeatScore(PostStatsVo postStats, Date creationDateTime, CommentEnum contentType) {
        // 1. 用户行为的基础得分（根据不同的行为进行加权）
        double userScore = calculateUserScore(postStats, contentType);

        // 2. 计算内容生命周期的衰减因子（根据创建时间和当前时间的差距）
        long daysSinceCreated = ChronoUnit.DAYS.between(
                creationDateTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(),
                LocalDateTime.now()
        );

        // 3. 时间衰减模型：早期内容热度更容易减缓
        double timeDecay = calculateTimeDecay(daysSinceCreated);

        // 4. 最终热度得分：考虑用户行为得分和时间衰减
        double heatScore = userScore * timeDecay;

        // 5. 日志输出，用于调试和查看评分情况
        log.info("Content Heat Score: {} (Time Decay: {}, User Score: {})", heatScore, timeDecay, userScore);

        return heatScore;
    }

    /**
     * 计算用户行为得分
     *
     * @param postStats   帖子统计数据
     * @param contentType 内容类型（学习资料/帖子）
     * @return 用户行为得分
     */
    private static double calculateUserScore(PostStatsVo postStats, CommentEnum contentType) {
        double likeWeight = getLikeWeight(contentType);
        double favoriteWeight = FAVORITE_WEIGHT;
        double viewWeight = getViewWeight(contentType);
        double commentWeight = COMMENT_WEIGHT;

        double userScore = (postStats.getLikes() * likeWeight) +
                (postStats.getCollects() * favoriteWeight) +
                Math.min((postStats.getViews() * viewWeight), MAX_VIEW_WEIGHT);

        if (contentType == CommentEnum.POST && postStats.getComments() != null) {
            userScore += Math.min((postStats.getComments() * commentWeight), MAX_COMMENT_WEIGHT);
        }

        // 添加用户类型权重
        if (postStats.isActiveUser()) {
            userScore *= ACTIVE_USER_WEIGHT;
        }
        if (postStats.isAssociationMember()) {
            userScore *= ASSOCIATION_MEMBER_WEIGHT;
        }
        return userScore;
    }

    /**
     * 获取点赞权重，根据内容类型调整
     *
     * @param contentType 内容类型（学习资料/帖子）
     * @return 点赞权重
     */
    private static double getLikeWeight(CommentEnum contentType) {
        if (contentType == CommentEnum.STUDYMATERIAL) {
            return 1.0;  // 学习资料的点赞权重
        }
        return 1.5;  // 普通帖子的点赞权重
    }

    /**
     * 获取浏览量权重，根据内容类型调整
     *
     * @param contentType 内容类型（学习资料/帖子）
     * @return 浏览量权重
     */
    private static double getViewWeight(CommentEnum contentType) {
        if (contentType == CommentEnum.STUDYMATERIAL) {
            return 0.8;  // 学习资料的浏览量权重
        }
        return 1.2;  // 普通帖子的浏览量权重
    }

    /**
     * 计算时间衰减因子（考虑内容的生命周期）
     *
     * @param daysSinceCreated 内容的创建天数
     * @return 时间衰减因子
     */
    private static double calculateTimeDecay(long daysSinceCreated) {
        // 基础的时间衰减
        double timeDecay = Math.pow(DECAY_RATE, daysSinceCreated);

        // 短期内容衰减因子可以调整
        if (daysSinceCreated < SHORT_LIVED_CONTENT_DAYS) {
            timeDecay *= 1.2; // 短期内容的衰减因子较慢
        }

        return timeDecay;
    }
}
